//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <wintypes.h>
#include <eltypes.h>
#include <stdio.h>
#include <stdlib.h>
_ELASTOS_NAMESPACE_USING
#include <sysconfig.h>


#define DEFAULT_CONFIG_FILENAME L"carhost.cfg"
#define DEFAULT_DEVICE_FILENAME L"default.dev"

#define SECTION_DEVICE      L"device"
#define SECTION_SETTINGS    L"settings"
#define SECTION_KEYBOARD    L"keyboard"
#define SECTION_MODULES     L"modules"
#define SECTION_DEBUG       L"debug"

#define EOS ('\0')      /* end-of-string indicator */

EXTERN_C wchar_t* __stdcall GetCommandLineW(VOID);
EXTERN_C unsigned long __stdcall GetCurrentDirectoryW(unsigned long, wchar_t*);
EXTERN_C wchar_t * CDECL _GetEnvironment(const wchar_t *envstring);

extern "C" ECode ConfigSetItem(
    /* [in] */ wchar_t *key,
    /* [in] */ wchar_t *value);

INLINE wchar_t * SkipHeadSpace(wchar_t *pwszValue)
{
    for (;' ' == *pwszValue || '\t' == *pwszValue; pwszValue++);
    return pwszValue;
}

INLINE void SkipTailSpace(wchar_t *pwszValue)
{
    for (;' ' == *pwszValue || '\t' == *pwszValue; pwszValue--);
    if (*(pwszValue + 1) != EOS) {
        *(pwszValue + 1) = EOS;
    }
}

static wchar_t * ScanToken(
    wchar_t *pwszStr, // the string to lexically analyze
    const wchar_t wchTermSym // a terminal symbol (list)
    )
{
    for (; *pwszStr; pwszStr++) {
        if (*pwszStr == wchTermSym) {
            *pwszStr = EOS;
            return pwszStr;
        }
    }
    return NULL; // Not found
}

//BUGBUG: if there is too much parameter to be deploied, _MAX_LINE may be short
//wchar_t *EnvParaSwitchover(wchar_t *pwszEnv, wchar_t wchToken)
//{
//    if (NULL == pwszEnv)return NULL;
//    wchar_t *pwszPara = NULL;
//    wchar_t *pwszTail = pwszEnv;
//    wchar_t * pwszEnvValue = NULL;
//    wchar_t *pwszRet = (wchar_t *)malloc(sizeof(wchar_t) * (_MAX_LINE + 1));
//    *pwszRet = NULL;
//
//    while (1) {
//        pwszPara = ScanToken(pwszTail, wchToken);
//        if (NULL == pwszPara) break;
//        wcscat(pwszRet, pwszTail);
//        pwszPara++;
//        pwszTail = ScanToken(pwszPara, wchToken);
//        if (NULL == pwszTail) return NULL;
//        pwszTail++;
//        if (L'%' == wchToken) {
//            pwszEnvValue= _GetEnvironment(pwszPara);
//            if (NULL == pwszEnvValue) {
//                wprintf(L"Unkonwn config environment parameter! \n");
//                return NULL;
//            }
//            wcscat(pwszRet, pwszEnvValue);
//        }
//        else if (L'$' == wchToken) {
//            pwszEnvValue = _wgetenv(pwszPara);
//            if (NULL == pwszEnvValue) {
//                wprintf(L"Unkonwn windows environment parameter! \n");
//                return NULL;
//            }
//            wcscat(pwszRet, pwszEnvValue);
//        }
//        else
//            return NULL;
//    }//while
//    wcscat(pwszRet, pwszTail);
//    return pwszRet;
//}

//put "-cfg" or "-dev" in pwszCompare to choice the Parameter
bool GetParameter(wchar_t* pFilename, wchar_t* pwszCompare)
{
    wchar_t *cmdLine;
    cmdLine = GetCommandLineW();
    cmdLine = wcsstr(cmdLine, pwszCompare);
    if (NULL != cmdLine) {
        cmdLine += wcslen(pwszCompare);
        cmdLine = SkipHeadSpace(cmdLine);
        for (; (*cmdLine != '\0') && (*cmdLine != ' ');) {
            *pFilename = *cmdLine;
            cmdLine++;
            pFilename++;
        }
        *pFilename = '\0';
        return true;
    }
    return false;
}

// Read a section in config file
static Boolean ReadSection(FILE *pCfgFile, wchar_t *pwszSecName)
{
    wchar_t wszLine[_MAX_LINE + 1];

    memset(wszLine, 0, sizeof(wszLine));

    if (fseek(pCfgFile, 0, SEEK_SET)) {
        wprintf(L"Error in seek device file!\n");
        return FALSE;
    }
    //STEP 1. Find Section

    while (fgetws(wszLine, _MAX_LINE, pCfgFile)) {
        wchar_t *pwszSecBegin = wszLine;

        pwszSecBegin = SkipHeadSpace(pwszSecBegin);

        if (*pwszSecBegin == L'#' ||
            *pwszSecBegin == L'\n' || *pwszSecBegin == EOS)
            continue; //skip comment
        else if (*pwszSecBegin++== L'[') {//Section Begin
#if defined(_DEBUG)
            wchar_t *pwszSecEnd =
#endif
            ScanToken(pwszSecBegin, L']');
            assert(pwszSecEnd);
            if (0 == wcscmp(pwszSecName, pwszSecBegin))
                goto FoundSection; //GOT
        }
    }
    return FALSE;

FoundSection:
    //STEP 2. Find Field
    while (fgetws(wszLine, _MAX_LINE, pCfgFile)) {
        wchar_t *pwszFldBegin, *pwszFldEnd, *pwszValueBgn, *pwszValueEnd;
        pwszFldBegin = wszLine;

        pwszFldBegin = SkipHeadSpace(pwszFldBegin);

        // skip comment
        if (*pwszFldBegin == L'[') return TRUE; // End of Section

        if (*pwszFldBegin == L'#' ||
            *pwszFldBegin == L'\n' || *pwszFldBegin == EOS)
            continue;

        pwszFldEnd = ScanToken(pwszFldBegin, L'=');
        if (NULL == pwszFldEnd) continue;

        SkipTailSpace(pwszFldEnd - 1);

        pwszValueBgn = pwszFldEnd + 1;
        pwszValueBgn = SkipHeadSpace(pwszValueBgn);
        assert(*pwszValueBgn != EOS);

        for (pwszValueEnd = pwszValueBgn;
            *pwszValueEnd != L'\r'
            && *pwszValueEnd != L'\n'
            && *pwszValueEnd != L'#'
            && *pwszValueEnd != EOS
            ;pwszValueEnd++);

        *pwszValueEnd = EOS;

        if (pwszValueEnd == pwszValueBgn) {
            wcscpy(pwszValueBgn, L" ");
        }
        else {
            SkipTailSpace(pwszValueEnd - 1);
        }

        // Insert config item into dictionary
        assert(wcslen(pwszFldBegin) <= _MAX_LINE);
        assert(wcslen(pwszValueBgn) <= _MAX_LINE);

        ConfigSetItem(pwszFldBegin, pwszValueBgn);
    }

    return TRUE;
}

Boolean AddDefaultPath(/* out */ wchar_t *pwszFileName)
{
    wchar_t *szFilePath;
    wchar_t szTempName[_MAX_PATH];

    wcscpy(szTempName, pwszFileName);

    // Get the full path of the config file
    szFilePath = _wgetenv(L"XDK_COMMON_CONFIG");
    if (szFilePath) {
        // The file is in the special config directory
        //wprintf(L"in AddDefaultPath EMULATOR_RESOURCE %s\n", szFilePath);
        wcscpy(pwszFileName, szFilePath);
    }
    else {
        // Think the file is in the current directory
        wcscpy(pwszFileName, L".");
    }
    wcscat(pwszFileName, L"\\");
    wcscat(pwszFileName, szTempName);
    assert(wcslen(pwszFileName) < _MAX_PATH);

    return TRUE;
}

EXTERN_C Boolean ReadConfigFile()
{
    FILE *pCfgFile;
    wchar_t wszCfgFileName[_MAX_PATH];
    wchar_t wszDevFileName[_MAX_PATH];

    //Read the appointed parameter
    if (GetParameter(wszCfgFileName, L"-cfg")) {
        //open the appointed CfgFile
        pCfgFile = _wfopen(wszCfgFileName, L"r");
        if (pCfgFile) goto READCFG;

        //open the added default path CfgFile
        AddDefaultPath(wszCfgFileName); // Not recommended
        pCfgFile = _wfopen(wszCfgFileName, L"r");
        if (pCfgFile) goto READCFG;

        wprintf(L"Can not open appointed config file!\n");
    }
    //open default config file
    wcscpy(wszCfgFileName, DEFAULT_CONFIG_FILENAME);
    AddDefaultPath(wszCfgFileName);

    pCfgFile = _wfopen(wszCfgFileName, L"r");
    if (!pCfgFile) {
        wprintf(L"Error in open config file!\n");
        return FALSE;
    }

READCFG:
//***************************************************************
//    wprintf(L"Software config file: %s\n",wszCfgFileName);
//******************************************************************
    // Read sections of config file
    ReadSection(pCfgFile, SECTION_DEVICE);
    ReadSection(pCfgFile, SECTION_MODULES);
    ReadSection(pCfgFile, SECTION_DEBUG);

    //Read the device file
    FILE *pDevFile;

    if (GetParameter(wszDevFileName, L"-dev")) {
        //open the appointed DevFile
        pDevFile = _wfopen(wszDevFileName, L"r");
        if(pDevFile) goto READDEV;

        //open the added default path DevFile
        AddDefaultPath(wszDevFileName);
        pDevFile = _wfopen(wszDevFileName, L"r");
        if(pDevFile) goto READDEV;

        wprintf(L"Can not open appointed devfile!\n");
    }

    //open the config appinted DevFile
    ConfigGetItemStr(L"DeviceFile", wszDevFileName);
    AddDefaultPath(wszDevFileName);
    pDevFile = _wfopen(wszDevFileName, L"r");
    if(pDevFile) goto READDEV;

    //open the default DevFile
    wprintf(L"Can not open device file in config!\n");
    wprintf(L"Open default device file!\n");
    wcscpy(wszDevFileName, DEFAULT_DEVICE_FILENAME);
    AddDefaultPath(wszDevFileName);
    pDevFile = _wfopen(wszDevFileName, L"r");
    if (!pDevFile) {
        wprintf(L"Error in open device file!\n");
        return FALSE;
    }

READDEV:
//********************************************************************
//    wprintf(L"Device file: %s\n",wszDevFileName);
//***********************************************************************
    // Read sections of device file
    ReadSection(pDevFile, SECTION_SETTINGS);
    ReadSection(pDevFile, SECTION_KEYBOARD);

    fclose(pCfgFile);
    fclose(pDevFile);

    return TRUE;
}
